/** * Admin menu pages, settings registration, and page renderers. */ class WBS_Settings { public function __construct() { add_action('admin_menu', array($this, 'add_menu_pages')); add_action('admin_init', array($this, 'register_settings')); add_action('admin_notices', array($this, 'display_admin_notices')); } public function add_menu_pages() { add_menu_page( __('Wondalizer SEO', 'wondalizer-basic-seo'), __('Wondalizer SEO', 'wondalizer-basic-seo'), 'manage_options', 'wbs-settings', array($this, 'render_settings_page'), 'dashicons-chart-line', 85 ); add_submenu_page( 'wbs-settings', __('Settings', 'wondalizer-basic-seo'), __('Settings', 'wondalizer-basic-seo'), 'manage_options', 'wbs-settings', array($this, 'render_settings_page') ); add_submenu_page( 'wbs-settings', __('Import SEO Data', 'wondalizer-basic-seo'), __('Import', 'wondalizer-basic-seo'), 'manage_options', 'wbs-import', array($this, 'render_import_page') ); add_submenu_page( 'wbs-settings', __('Redirects', 'wondalizer-basic-seo'), __('Redirects', 'wondalizer-basic-seo'), 'manage_options', 'wbs-redirects', array($this, 'render_redirects_page') ); add_submenu_page( 'wbs-settings', __('About Wondalizer', 'wondalizer-basic-seo'), __('About', 'wondalizer-basic-seo'), 'manage_options', 'wbs-about', array($this, 'render_about_page') ); } public function register_settings() { register_setting('wbs_settings_group', 'wbs_default_og_image', 'esc_url_raw'); register_setting('wbs_settings_group', 'wbs_twitter_site', 'sanitize_text_field'); register_setting('wbs_settings_group', 'wbs_facebook_app_id', 'sanitize_text_field'); register_setting('wbs_settings_group', 'wbs_default_title_template', 'sanitize_text_field'); register_setting('wbs_settings_group', 'wbs_default_desc_template', 'sanitize_textarea_field'); register_setting('wbs_settings_group', 'wbs_bing_verify', 'sanitize_text_field'); register_setting('wbs_settings_group', 'wbs_yandex_verify', 'sanitize_text_field'); register_setting('wbs_settings_group', 'wbs_google_verify', 'sanitize_text_field'); register_setting('wbs_settings_group', 'wbs_enabled_post_types', array($this, 'sanitize_post_types')); register_setting('wbs_settings_group', 'wbs_enable_edd', 'sanitize_text_field'); register_setting('wbs_settings_group', 'wbs_enable_woocommerce', 'sanitize_text_field'); register_setting('wbs_settings_group', 'wbs_custom_post_types', 'sanitize_text_field'); register_setting('wbs_settings_group', 'wbs_enable_custom_fields', 'sanitize_text_field'); register_setting('wbs_settings_group', 'wbs_remove_shortcodes', 'sanitize_text_field'); register_setting('wbs_settings_group', 'wbs_remove_iframes', 'sanitize_text_field'); } public function sanitize_post_types($input) { if (!is_array($input)) { return array('post', 'page'); } $valid = array(); $all = get_post_types(array('public' => true), 'names'); foreach ($input as $pt) { if (isset($all[$pt])) { $valid[] = sanitize_text_field($pt); } } return empty($valid) ? array('post', 'page') : $valid; } public function display_admin_notices() { if (isset($_GET['wbs_saved']) && current_user_can('manage_options')) { echo '

' . esc_html__('Settings saved successfully.', 'wondalizer-basic-seo') . '

'; } } public function render_settings_page() { $all_post_types = get_post_types(array('public' => true), 'objects'); $enabled = get_option('wbs_enabled_post_types', array('post', 'page')); if (!is_array($enabled)) { $enabled = array('post', 'page'); } echo '
'; echo '

' . esc_html(get_admin_page_title()) . '

'; echo '
'; ob_start(); settings_fields('wbs_settings_group'); $wbs_tmp = ob_get_clean(); echo ' ' . $wbs_tmp; ob_start(); do_settings_sections('wbs_settings_group'); $wbs_tmp = ob_get_clean(); echo ' ' . $wbs_tmp; echo '
'; echo '
'; echo '

' . __('Social Defaults', 'wondalizer-basic-seo') . '

'; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo '
'; echo ' '; echo '

' . __('Fallback Open Graph image for all pages. Recommended 1200×630 px.', 'wondalizer-basic-seo') . '

'; echo '
'; echo ' '; echo '
'; echo ' '; echo '
'; echo '
'; echo '
'; echo '

' . __('Title & Description Templates', 'wondalizer-basic-seo') . '

'; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo '
'; echo ' '; echo '

' . __('Variables: %%title%%, %%sitename%%', 'wondalizer-basic-seo') . '

'; echo '
'; echo ' '; echo '

' . __('Variables: %%excerpt%%, %%sitename%%', 'wondalizer-basic-seo') . '

'; echo '
'; echo '
'; echo '
'; echo '

' . __('Search Engine Verification', 'wondalizer-basic-seo') . '

'; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo '
'; echo ' '; echo '

' . __('Paste the full meta tag content or just the verification code.', 'wondalizer-basic-seo') . '

'; echo '
'; echo ' '; echo '

' . __('Bing verification code (msvalidate.01).', 'wondalizer-basic-seo') . '

'; echo '
'; echo ' '; echo '

' . __('Yandex verification code.', 'wondalizer-basic-seo') . '

'; echo '
'; echo '
'; echo '
'; echo '

' . __('Post Types & Compatibility', 'wondalizer-basic-seo') . '

'; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo '
' . __('Enabled Post Types', 'wondalizer-basic-seo') . ''; echo '
'; foreach ($all_post_types as $pt => $obj) { echo ' '; } echo '
'; echo '

' . __('Select which post types should have SEO meta boxes and quick edit support.', 'wondalizer-basic-seo') . '

'; echo '
' . __('eCommerce Plugins', 'wondalizer-basic-seo') . ''; echo '
'; echo ' '; echo '
'; echo ' '; echo '

' . __('Add custom post type slugs manually. These will be checked and enabled if they exist.', 'wondalizer-basic-seo') . '

'; echo '
' . __('Custom Fields Support', 'wondalizer-basic-seo') . ''; echo ' '; echo '
' . __('Shortcode Removal', 'wondalizer-basic-seo') . ''; echo ' '; echo '

' . __('When enabled, shortcode tags are stripped from excerpts and meta descriptions so they start from real text. This does not affect shortcodes on the actual page.', 'wondalizer-basic-seo') . '

'; echo '
' . __('Embed / Frame Removal', 'wondalizer-basic-seo') . ''; echo ' '; echo '

' . __('When enabled, all iframe, embed and object tags are stripped from content and excerpts before they reach crawlers. This keeps meta descriptions clean and prevents raw embed markup from appearing in search results.', 'wondalizer-basic-seo') . '

'; echo '
'; echo '
'; echo '
'; ob_start(); submit_button(__('Save Settings', 'wondalizer-basic-seo'), 'primary', 'submit', true, array('class' => 'wbs-save-btn')); $wbs_tmp = ob_get_clean(); echo ' ' . $wbs_tmp; echo '
'; echo '
'; } public function render_import_page() { $import = new WBS_Import(); $yoast_count = $import->count_importable_posts('yoast'); $rankmath_count = $import->count_importable_posts('rankmath'); $aioseo_count = $import->count_importable_posts('aioseo'); echo '
'; echo '

' . esc_html(get_admin_page_title()) . '

'; echo '

' . __('Import SEO data from other plugins. Only copies needed data (title, description, social meta). Data is detected by scanning the database for existing meta keys.', 'wondalizer-basic-seo') . '

'; echo '
'; echo '
'; echo '

' . __('Yoast SEO', 'wondalizer-basic-seo') . '

'; if (($yoast_count > 0)) { ob_start(); printf(esc_html__('Detected! %d posts/pages with data.', 'wondalizer-basic-seo'), $yoast_count); $wbs_tmp = ob_get_clean(); echo '

' . $wbs_tmp . '

'; echo '
'; ob_start(); wp_nonce_field('wbs_import_nonce'); $wbs_tmp = ob_get_clean(); echo ' ' . $wbs_tmp; echo ' '; echo ' '; echo ' '; echo '
'; } else { echo '

' . __('No Yoast SEO data found in database.', 'wondalizer-basic-seo') . '

'; } echo '
'; echo '
'; echo '

' . __('Rank Math', 'wondalizer-basic-seo') . '

'; if (($rankmath_count > 0)) { ob_start(); printf(esc_html__('Detected! %d posts/pages with data.', 'wondalizer-basic-seo'), $rankmath_count); $wbs_tmp = ob_get_clean(); echo '

' . $wbs_tmp . '

'; echo '
'; ob_start(); wp_nonce_field('wbs_import_nonce'); $wbs_tmp = ob_get_clean(); echo ' ' . $wbs_tmp; echo ' '; echo ' '; echo ' '; echo '
'; } else { echo '

' . __('No Rank Math data found in database.', 'wondalizer-basic-seo') . '

'; } echo '
'; echo '
'; echo '

' . __('All in One SEO', 'wondalizer-basic-seo') . '

'; if (($aioseo_count > 0)) { ob_start(); printf(esc_html__('Detected! %d posts/pages with data.', 'wondalizer-basic-seo'), $aioseo_count); $wbs_tmp = ob_get_clean(); echo '

' . $wbs_tmp . '

'; echo '
'; ob_start(); wp_nonce_field('wbs_import_nonce'); $wbs_tmp = ob_get_clean(); echo ' ' . $wbs_tmp; echo ' '; echo ' '; echo ' '; echo '
'; } else { echo '

' . __('No AIOSEO data found in database.', 'wondalizer-basic-seo') . '

'; } echo '
'; echo '
'; if ((isset($_GET['imported']))) { echo '
'; ob_start(); printf(esc_html__('Imported %d posts/pages successfully.', 'wondalizer-basic-seo'), intval($_GET['imported'])); $wbs_tmp = ob_get_clean(); echo '

' . $wbs_tmp . '

'; echo '
'; } if ((isset($_GET['import_error']))) { echo '
'; echo '

' . esc_html__('Import failed. Please try again.', 'wondalizer-basic-seo') . '

'; echo '
'; } echo '
'; } public function render_redirects_page() { $redirects = new WBS_Redirects(); $redirects->render_admin_page(); } public function render_about_page() { echo '
'; echo '

' . esc_html(get_admin_page_title()) . '

'; echo '
'; echo '
'; echo ' '; echo '

' . __('Listen at HearThis', 'wondalizer-basic-seo') . '

'; echo '
'; echo '

' . __('Wondalizer Basic SEO — Powerful SEO made simple for every WordPress site.', 'wondalizer-basic-seo') . '

'; echo '
'; echo '
'; echo '
'; echo '

' . __('Support Great App Development', 'wondalizer-basic-seo') . '

'; echo '

' . __('Your donation helps us keep improving Wondalizer Basic SEO and building new features for the WordPress community.', 'wondalizer-basic-seo') . '

'; echo ' '; echo '
'; echo ' '; echo ' '; echo '
'; echo '
'; echo '
'; echo '

' . __('Wondalizer on HearThis', 'wondalizer-basic-seo') . '

'; echo '
'; echo ' '; echo ' '; echo '
'; echo '
'; echo '
'; echo '

' . __('About the Plugin', 'wondalizer-basic-seo') . '

'; echo '
'; echo '
'; echo ' '; echo '
'; echo ' ' . __('Social Card Previews', 'wondalizer-basic-seo') . ''; echo '

' . __('Live Google, Facebook, and X/Twitter previews in Classic Editor and Gutenberg.', 'wondalizer-basic-seo') . '

'; echo '
'; echo '
'; echo '
'; echo ' '; echo '
'; echo ' ' . __('Universal Social Cards', 'wondalizer-basic-seo') . ''; echo '

' . __('Optimized for Facebook, X (Twitter), TikTok, Instagram, WhatsApp, LinkedIn, Discord, Slack, Apple/iOS.', 'wondalizer-basic-seo') . '

'; echo '
'; echo '
'; echo '
'; echo ' '; echo '
'; echo ' ' . __('Character Counters', 'wondalizer-basic-seo') . ''; echo '

' . __('Real-time counters — green (good), yellow (okay), red (too long).', 'wondalizer-basic-seo') . '

'; echo '
'; echo '
'; echo '
'; echo ' '; echo '
'; echo ' ' . __('One-Click Import', 'wondalizer-basic-seo') . ''; echo '

' . __('Import from Yoast SEO, Rank Math, and All in One SEO. No data loss.', 'wondalizer-basic-seo') . '

'; echo '
'; echo '
'; echo '
'; echo ' '; echo '
'; echo ' ' . __('Redirect Manager', 'wondalizer-basic-seo') . ''; echo '

' . __('301/302 redirects with exact, starts-with, ends-with, and contains matching.', 'wondalizer-basic-seo') . '

'; echo '
'; echo '
'; echo '
'; echo ' '; echo '
'; echo ' ' . __('eCommerce Ready', 'wondalizer-basic-seo') . ''; echo '

' . __('Full support for Easy Digital Downloads and WooCommerce products.', 'wondalizer-basic-seo') . '

'; echo '
'; echo '
'; echo '
'; echo ' '; echo '
'; echo ' ' . __('Quick Edit SEO', 'wondalizer-basic-seo') . ''; echo '

' . __('Edit SEO title, description, and focus keyword directly from the post list.', 'wondalizer-basic-seo') . '

'; echo '
'; echo '
'; echo '
'; echo ' '; echo '
'; echo ' ' . __('Search Engine Verification', 'wondalizer-basic-seo') . ''; echo '

' . __('Google, Bing, and Yandex meta verification tags.', 'wondalizer-basic-seo') . '

'; echo '
'; echo '
'; echo '
'; echo '
'; echo '
'; echo ' '; echo '
'; } } /** * Classic Editor meta box with tabs, character counters, media upload, * social card previews, auto-fill, and save confirmation. */ class WBS_Meta_Box { public function __construct() { add_action('add_meta_boxes', array($this, 'add_meta_boxes')); add_action('save_post', array($this, 'save_meta'), 10, 2); add_action('admin_notices', array($this, 'display_save_notice')); } public function add_meta_boxes() { $post_types = wbs_get_supported_post_types(); foreach ($post_types as $pt) { add_meta_box( 'wbs_seo_meta_box', __('Wondalizer SEO', 'wondalizer-basic-seo'), array($this, 'render_meta_box'), $pt, 'normal', 'high' ); } } public function display_save_notice() { $screen = get_current_screen(); if (!$screen || ($screen->base !== 'post' && $screen->base !== 'post-new')) { return; } if (isset($_GET['message']) && in_array(intval($_GET['message']), array(1, 6))) { echo '

' . esc_html__('SEO data saved with post.', 'wondalizer-basic-seo') . '

'; } } public function render_meta_box($post) { wp_nonce_field('wbs_save_meta', 'wbs_meta_nonce'); $fields = $this->get_fields($post->ID); $post_title = get_the_title($post->ID); $post_excerpt = $this->get_excerpt($post); $permalink = get_permalink($post->ID); $default_image = get_option('wbs_default_og_image'); $featured_image = has_post_thumbnail($post->ID) ? get_the_post_thumbnail_url($post->ID, 'full') : ''; echo '
'; echo ' '; echo ' '; echo '
'; echo '

' . __('Social Card Previews', 'wondalizer-basic-seo') . '

'; echo '
'; echo ' '; echo ' '; echo ' '; echo '
'; echo '
'; echo '
'; echo '
' . esc_html(parse_url($permalink, PHP_URL_HOST) ?: parse_url(home_url(), PHP_URL_HOST)) . '
'; echo '
' . esc_html($fields['seo_title'] ?: $post_title) . '
'; echo '
' . esc_html($fields['seo_description'] ?: $post_excerpt) . '
'; echo '
'; echo '
'; echo '
'; echo '
'; echo '
'; echo ' '; echo '
'; echo '
'; echo '
' . esc_html(parse_url($permalink, PHP_URL_HOST) ?: parse_url(home_url(), PHP_URL_HOST)) . '
'; echo '
' . esc_html($fields['facebook_title'] ?: $fields['og_title'] ?: $fields['seo_title'] ?: $post_title) . '
'; echo '
' . esc_html($fields['facebook_description'] ?: $fields['og_description'] ?: $fields['seo_description'] ?: $post_excerpt) . '
'; echo '
'; echo '
'; echo '
'; echo '
'; echo '
'; echo '
'; echo ' '; echo '
'; echo '
'; echo '
' . esc_html($fields['twitter_title'] ?: $fields['seo_title'] ?: $post_title) . '
'; echo '
' . esc_html($fields['twitter_description'] ?: $fields['seo_description'] ?: $post_excerpt) . '
'; echo '
' . esc_html(parse_url($permalink, PHP_URL_HOST) ?: parse_url(home_url(), PHP_URL_HOST)) . '
'; echo '
'; echo '
'; echo '
'; echo '
'; echo ' '; echo '
'; echo ' '; echo ' '; echo ' '; echo ' '; echo '
'; echo ' '; echo '
'; echo '
'; echo '
'; echo ' '; echo ' '; echo ' 0 / 60'; echo ' ' . __('Recommended: 60 characters max for Google. Green = good, Yellow = okay, Red = too long.', 'wondalizer-basic-seo') . ''; echo '
'; echo '
'; echo '
'; echo '
'; echo ' '; echo ' '; echo ' 0 / 160'; echo ' ' . __('Recommended: 160 characters max.', 'wondalizer-basic-seo') . ''; echo '
'; echo '
'; echo '
'; echo '
'; echo ' '; echo ' '; echo '
'; echo '
'; echo ' '; echo ' '; echo '
'; echo '
'; echo '
'; echo '
'; echo ' '; echo ' '; echo '
'; echo '
'; echo '
'; echo ' '; echo '
'; echo '
'; echo '
'; echo ' '; echo ' '; echo ' 0 / 100'; echo '
'; echo '
'; echo '
'; echo '
'; echo ' '; echo ' '; echo ' 0 / 200'; echo '
'; echo '
'; echo '
'; echo '
'; echo ' '; echo ' '; echo ' '; echo '
'; echo ' '; echo ' '; echo '
'; echo '
'; if (($fields['facebook_image_url'])) { echo ' Facebook preview'; } echo '
'; echo ' ' . __('Recommended: 1200×630 px for Facebook wide card. Minimum 600×315 px.', 'wondalizer-basic-seo') . ''; echo '
'; echo '
'; echo '
'; echo ' '; echo '
'; echo '
'; echo '
'; echo ' '; echo ' '; echo '
'; echo '
'; echo '
'; echo '
'; echo ' '; echo ' '; echo ' 0 / 70'; echo '
'; echo '
'; echo '
'; echo '
'; echo ' '; echo ' '; echo ' 0 / 200'; echo '
'; echo '
'; echo '
'; echo '
'; echo ' '; echo ' '; echo ' '; echo '
'; echo ' '; echo ' '; echo '
'; echo '
'; if (($fields['twitter_image_url'])) { echo ' Twitter preview'; } echo '
'; echo ' ' . __('Recommended: 1200×600 px for large image card, 144×144 px for summary card.', 'wondalizer-basic-seo') . ''; echo '
'; echo '
'; echo '
'; echo ' '; echo '
'; echo '
'; echo '
'; echo ' '; echo ' '; echo ' 0 / 100'; echo '
'; echo '
'; echo '
'; echo '
'; echo ' '; echo ' '; echo ' 0 / 200'; echo '
'; echo '
'; echo '
'; echo '
'; echo ' '; echo ' '; echo ' '; echo '
'; echo ' '; echo ' '; echo '
'; echo '
'; if (($fields['og_image_url'])) { echo ' OG preview'; } echo '
'; echo ' ' . __('Recommended: 1200×630 px. Used as fallback for all social platforms.', 'wondalizer-basic-seo') . ''; echo '
'; echo '
'; echo '
'; echo '
'; } public function save_meta($post_id, $post) { if (!isset($_POST['wbs_meta_nonce']) || !wp_verify_nonce($_POST['wbs_meta_nonce'], 'wbs_save_meta')) { return; } if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { return; } if (!current_user_can('edit_post', $post_id)) { return; } $fields = array( 'wbs_seo_title', 'wbs_seo_description', 'wbs_focus_keyword', 'wbs_canonical_url', 'wbs_og_title', 'wbs_og_description', 'wbs_og_image_id', 'wbs_og_image_url', 'wbs_facebook_title', 'wbs_facebook_description', 'wbs_facebook_image_id', 'wbs_facebook_image_url', 'wbs_twitter_title', 'wbs_twitter_description', 'wbs_twitter_image_id', 'wbs_twitter_image_url', 'wbs_twitter_card' ); foreach ($fields as $field) { if (isset($_POST[$field])) { $value = (strpos($field, '_url') !== false || strpos($field, 'canonical') !== false) ? esc_url_raw(wp_unslash($_POST[$field])) : sanitize_text_field(wp_unslash($_POST[$field])); update_post_meta($post_id, $field, $value); } } update_post_meta($post_id, 'wbs_robots_noindex', isset($_POST['wbs_robots_noindex']) ? 1 : 0); update_post_meta($post_id, 'wbs_robots_nofollow', isset($_POST['wbs_robots_nofollow']) ? 1 : 0); } private function get_fields($post_id) { return array( 'seo_title' => get_post_meta($post_id, 'wbs_seo_title', true), 'seo_description' => get_post_meta($post_id, 'wbs_seo_description', true), 'focus_keyword' => get_post_meta($post_id, 'wbs_focus_keyword', true), 'canonical_url' => get_post_meta($post_id, 'wbs_canonical_url', true), 'robots_noindex' => get_post_meta($post_id, 'wbs_robots_noindex', true), 'robots_nofollow' => get_post_meta($post_id, 'wbs_robots_nofollow', true), 'og_title' => get_post_meta($post_id, 'wbs_og_title', true), 'og_description' => get_post_meta($post_id, 'wbs_og_description', true), 'og_image_id' => get_post_meta($post_id, 'wbs_og_image_id', true), 'og_image_url' => get_post_meta($post_id, 'wbs_og_image_url', true), 'facebook_title' => get_post_meta($post_id, 'wbs_facebook_title', true), 'facebook_description' => get_post_meta($post_id, 'wbs_facebook_description', true), 'facebook_image_id' => get_post_meta($post_id, 'wbs_facebook_image_id', true), 'facebook_image_url' => get_post_meta($post_id, 'wbs_facebook_image_url', true), 'twitter_title' => get_post_meta($post_id, 'wbs_twitter_title', true), 'twitter_description' => get_post_meta($post_id, 'wbs_twitter_description', true), 'twitter_image_id' => get_post_meta($post_id, 'wbs_twitter_image_id', true), 'twitter_image_url' => get_post_meta($post_id, 'wbs_twitter_image_url', true), 'twitter_card' => get_post_meta($post_id, 'wbs_twitter_card', true) ?: 'summary_large_image', ); } private function get_excerpt($post) { if (!empty($post->post_excerpt)) { return wp_strip_all_tags($post->post_excerpt); } return wp_trim_words(wp_strip_all_tags($post->post_content), 30, ''); } } /** * Redirect manager with pattern matching. */ class WBS_Redirects { private $table; public function __construct() { global $wpdb; $this->table = $wpdb->prefix . 'wbs_redirects'; add_action('template_redirect', array($this, 'check_redirects'), 1); add_action('admin_post_wbs_save_redirect', array($this, 'save_redirect')); add_action('admin_post_wbs_delete_redirect', array($this, 'delete_redirect')); } public function check_redirects() { if (is_admin()) { return; } $request_uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : ''; $request_path = parse_url($request_uri, PHP_URL_PATH) ?: $request_uri; global $wpdb; $redirects = $wpdb->get_results("SELECT * FROM {$this->table} WHERE status = 1 ORDER BY id DESC"); foreach ($redirects as $redirect) { $source = $redirect->source_url; $match = false; switch ($redirect->match_type) { case 'exact': $match = ($request_uri === $source || $request_path === $source); break; case 'starts_with': $match = (strpos($request_uri, $source) === 0 || strpos($request_path, $source) === 0); break; case 'ends_with': $match = (substr($request_uri, -strlen($source)) === $source || substr($request_path, -strlen($source)) === $source); break; case 'contains': $match = (strpos($request_uri, $source) !== false || strpos($request_path, $source) !== false); break; } if ($match) { $wpdb->query($wpdb->prepare( "UPDATE {$this->table} SET hits = hits + 1 WHERE id = %d", $redirect->id )); $code = intval($redirect->redirect_type); wp_redirect(esc_url_raw($redirect->target_url), $code); exit; } } } public function save_redirect() { if (!current_user_can('manage_options')) { wp_die(__('Permission denied.', 'wondalizer-basic-seo')); } check_admin_referer('wbs_redirect_nonce'); global $wpdb; $id = isset($_POST['redirect_id']) ? intval($_POST['redirect_id']) : 0; $source = isset($_POST['source_url']) ? sanitize_text_field(wp_unslash($_POST['source_url'])) : ''; $match_type = isset($_POST['match_type']) ? sanitize_text_field(wp_unslash($_POST['match_type'])) : 'exact'; $target = isset($_POST['target_url']) ? esc_url_raw(wp_unslash($_POST['target_url'])) : ''; $type = isset($_POST['redirect_type']) ? intval($_POST['redirect_type']) : 301; $status = isset($_POST['status']) ? 1 : 0; if (empty($source) || empty($target)) { wp_redirect(admin_url('admin.php?page=wbs-redirects&error=1')); exit; } $data = array( 'source_url' => $source, 'match_type' => $match_type, 'target_url' => $target, 'redirect_type' => $type, 'status' => $status, ); if ($id > 0) { $wpdb->update($this->table, $data, array('id' => $id)); } else { $wpdb->insert($this->table, $data); } wp_redirect(admin_url('admin.php?page=wbs-redirects&saved=1')); exit; } public function delete_redirect() { if (!current_user_can('manage_options')) { wp_die(__('Permission denied.', 'wondalizer-basic-seo')); } check_admin_referer('wbs_delete_redirect'); global $wpdb; $id = isset($_GET['id']) ? intval($_GET['id']) : 0; if ($id > 0) { $wpdb->delete($this->table, array('id' => $id)); } wp_redirect(admin_url('admin.php?page=wbs-redirects&deleted=1')); exit; } public function render_admin_page() { global $wpdb; $redirects = $wpdb->get_results("SELECT * FROM {$this->table} ORDER BY id DESC"); $edit = null; if (isset($_GET['edit'])) { $edit = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$this->table} WHERE id = %d", intval($_GET['edit']))); } echo '
'; echo '

' . esc_html(get_admin_page_title()) . '

'; if ((isset($_GET['saved']))) { echo '

' . __('Redirect saved.', 'wondalizer-basic-seo') . '

'; } if ((isset($_GET['deleted']))) { echo '

' . __('Redirect deleted.', 'wondalizer-basic-seo') . '

'; } if ((isset($_GET['error']))) { echo '

' . __('Source and Target URL are required.', 'wondalizer-basic-seo') . '

'; } echo '
'; echo '

' . ($edit ? esc_html__('Edit Redirect', 'wondalizer-basic-seo') : esc_html__('Add New Redirect', 'wondalizer-basic-seo')) . '

'; echo '
'; ob_start(); wp_nonce_field('wbs_redirect_nonce'); $wbs_tmp = ob_get_clean(); echo ' ' . $wbs_tmp; echo ' '; if (($edit)) { echo ' '; } echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo '
'; echo ' '; echo '

' . __('The URL to match. Can be relative (e.g. /old-page/) or absolute.', 'wondalizer-basic-seo') . '

'; echo '
'; echo ' '; echo '
'; echo ' '; echo '
'; echo ' '; echo '
' . __('Status', 'wondalizer-basic-seo') . ''; echo ' '; echo '
'; ob_start(); submit_button($edit ? __('Update Redirect', 'wondalizer-basic-seo') : __('Add Redirect', 'wondalizer-basic-seo')); $wbs_tmp = ob_get_clean(); echo ' ' . $wbs_tmp; echo '
'; echo '
'; echo '

' . __('Existing Redirects', 'wondalizer-basic-seo') . '

'; echo '
'; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; if ((empty($redirects))) { echo ' '; } else { foreach ($redirects as $r) { echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; echo ' '; } } echo ' '; echo '
' . __('Source', 'wondalizer-basic-seo') . '' . __('Match', 'wondalizer-basic-seo') . '' . __('Target', 'wondalizer-basic-seo') . '' . __('Type', 'wondalizer-basic-seo') . '' . __('Hits', 'wondalizer-basic-seo') . '' . __('Status', 'wondalizer-basic-seo') . '' . __('Actions', 'wondalizer-basic-seo') . '
' . __('No redirects found.', 'wondalizer-basic-seo') . '
' . esc_html($r->source_url) . '' . esc_html($r->match_type) . '' . esc_html($r->target_url) . '' . ($r->redirect_type == 301 ? '301' : '302') . '' . number_format($r->hits) . '' . ($r->status ? '' . __('Active', 'wondalizer-basic-seo') . '' : '' . __('Inactive', 'wondalizer-basic-seo') . '') . ''; echo ' ' . __('Edit', 'wondalizer-basic-seo') . ' |'; echo ' ' . __('Delete', 'wondalizer-basic-seo') . ''; echo '
'; echo '
'; echo '
'; } } /** * Quick Edit SEO fields for Posts and Pages list tables. * Adds classic-editor-style SEO fields to the Quick Edit panel. */ class WBS_Quick_Edit { public function __construct() { $post_types = wbs_get_supported_post_types(); foreach ($post_types as $pt) { add_action('quick_edit_custom_box', array($this, 'quick_edit_fields'), 10, 2); add_action('save_post', array($this, 'save_quick_edit'), 10, 2); add_filter('manage_' . $pt . '_posts_columns', array($this, 'add_seo_columns')); add_action('manage_' . $pt . '_posts_custom_column', array($this, 'render_seo_columns'), 10, 2); add_action('manage_' . $pt . '_posts_custom_column', array($this, 'inline_data'), 10, 2); } add_action('admin_footer', array($this, 'quick_edit_js')); } public function add_seo_columns($columns) { $new = array(); foreach ($columns as $key => $label) { $new[$key] = $label; if ($key === 'title') { $new['wbs_seo_title_col'] = __('SEO Title', 'wondalizer-basic-seo'); $new['wbs_seo_desc_col'] = __('SEO Desc', 'wondalizer-basic-seo'); } } return $new; } public function render_seo_columns($column, $post_id) { if ($column === 'wbs_seo_title_col') { $title = get_post_meta($post_id, 'wbs_seo_title', true); if (empty($title)) { echo ''; } else { echo esc_html(mb_strimwidth($title, 0, 40, '…')); } } if ($column === 'wbs_seo_desc_col') { $desc = get_post_meta($post_id, 'wbs_seo_description', true); if (empty($desc)) { echo ''; } else { echo esc_html(mb_strimwidth($desc, 0, 50, '…')); } } } public function inline_data($column_name, $post_id) { if ($column_name !== 'wbs_seo_title_col') { return; } $fields = array( 'seo_title' => get_post_meta($post_id, 'wbs_seo_title', true), 'seo_desc' => get_post_meta($post_id, 'wbs_seo_description', true), 'focus_keyword' => get_post_meta($post_id, 'wbs_focus_keyword', true), 'canonical' => get_post_meta($post_id, 'wbs_canonical_url', true), 'noindex' => get_post_meta($post_id, 'wbs_robots_noindex', true), 'nofollow' => get_post_meta($post_id, 'wbs_robots_nofollow', true), 'excerpt' => get_post_field('post_excerpt', $post_id), ); echo ' '; } public function quick_edit_fields($column_name, $post_type) { if ($column_name !== 'wbs_seo_title_col') { return; } echo '
'; echo '
'; echo '

'; echo ' '; echo ' ' . __('Wondalizer SEO — Quick Edit', 'wondalizer-basic-seo'); echo '

'; echo '
'; echo ' '; echo '
'; echo '
'; echo ' '; echo '
'; echo '
'; echo ' '; echo ' '; echo '
'; echo '
'; echo ' '; echo ' '; echo '
'; echo '
'; echo ' '; echo '
'; echo '
'; echo '
'; } public function save_quick_edit($post_id, $post) { if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { return; } if (!current_user_can('edit_post', $post_id)) { return; } if (!isset($_REQUEST['_inline_edit']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_REQUEST['_inline_edit'])), 'inlineeditnonce')) { return; } if (isset($_REQUEST['wbs_qe_seo_title'])) { update_post_meta($post_id, 'wbs_seo_title', sanitize_text_field(wp_unslash($_REQUEST['wbs_qe_seo_title']))); } if (isset($_REQUEST['wbs_qe_seo_description'])) { update_post_meta($post_id, 'wbs_seo_description', sanitize_text_field(wp_unslash($_REQUEST['wbs_qe_seo_description']))); } if (isset($_REQUEST['wbs_qe_focus_keyword'])) { update_post_meta($post_id, 'wbs_focus_keyword', sanitize_text_field(wp_unslash($_REQUEST['wbs_qe_focus_keyword']))); } if (isset($_REQUEST['wbs_qe_canonical_url'])) { update_post_meta($post_id, 'wbs_canonical_url', esc_url_raw(wp_unslash($_REQUEST['wbs_qe_canonical_url']))); } update_post_meta($post_id, 'wbs_robots_noindex', isset($_REQUEST['wbs_qe_robots_noindex']) ? 1 : 0); update_post_meta($post_id, 'wbs_robots_nofollow', isset($_REQUEST['wbs_qe_robots_nofollow']) ? 1 : 0); } public function quick_edit_js() { $screen = get_current_screen(); if (!$screen || $screen->base !== 'edit') { return; } echo ' '; } }